package org.budo.druid.filter.log.slf4j;

import java.util.ArrayList;
import java.util.List;

import com.alibaba.druid.proxy.jdbc.CallableStatementProxy;
import com.alibaba.druid.proxy.jdbc.JdbcParameter;
import com.alibaba.druid.proxy.jdbc.PreparedStatementProxy;
import com.alibaba.druid.proxy.jdbc.ResultSetProxy;
import com.alibaba.druid.proxy.jdbc.StatementProxy;
import com.alibaba.druid.sql.SQLUtils;

/**
 * @author li
 * @version 1 (2015年12月21日 下午3:53:24)
 * @since Java7
 * @see com.alibaba.druid.filter.logging.Slf4jLogFilter
 */
public class Slf4jLogFilter extends com.alibaba.druid.filter.logging.Slf4jLogFilter {
    /**
     * statementExecuteAfter
     */
    protected void statementExecuteAfter(StatementProxy statement, String sql, boolean firstResult) {
        this.logExecutableSql(statement, sql);

        if (this.isStatementExecuteAfterLogEnabled() && isStatementLogEnabled()) {
            statement.setLastExecuteTimeNano();
            double nanos = statement.getLastExecuteTimeNano();
            double millis = nanos / (1000 * 1000);

            this.statementLog("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) + "} executed. " + millis + " millis. " + sql);
        }
    }

    /**
     * statementExecuteBatchAfter
     */
    protected void statementExecuteBatchAfter(StatementProxy statement, int[] result) {
        String sql;
        if (statement instanceof PreparedStatementProxy) {
            sql = ((PreparedStatementProxy) statement).getSql();
        } else {
            sql = statement.getBatchSql();
        }

        this.logExecutableSql(statement, sql);

        if (this.isStatementExecuteBatchAfterLogEnabled() && isStatementLogEnabled()) {
            statement.setLastExecuteTimeNano();
            double nanos = statement.getLastExecuteTimeNano();
            double millis = nanos / (1000 * 1000);

            this.statementLog("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) + "} batch executed. " + millis + " millis. " + sql);
        }
    }

    /**
     * statementExecuteQueryAfter
     */
    protected void statementExecuteQueryAfter(StatementProxy statement, String sql, ResultSetProxy resultSet) {
        this.logExecutableSql(statement, sql);

        if (this.isStatementExecuteQueryAfterLogEnabled() && isStatementLogEnabled()) {
            statement.setLastExecuteTimeNano();
            double nanos = statement.getLastExecuteTimeNano();
            double millis = nanos / (1000 * 1000);

            this.statementLog("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) + ", rs-" + resultSet.getId() + "} query executed. " + millis + " millis. " + sql);
        }
    }

    /**
     * statementExecuteUpdateAfter
     */
    protected void statementExecuteUpdateAfter(StatementProxy statement, String sql, int updateCount) {
        this.logExecutableSql(statement, sql);

        if (this.isStatementExecuteUpdateAfterLogEnabled() && isStatementLogEnabled()) {
            statement.setLastExecuteTimeNano();
            double nanos = statement.getLastExecuteTimeNano();
            double millis = nanos / (1000 * 1000);

            this.statementLog("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) + "} update executed. effort " + updateCount + ". " + millis + " millis. " + sql);
        }
    }

    /**
     * logExecutableSql
     */
    protected void logExecutableSql(StatementProxy statement, String sql) {
        if (!this.isStatementExecutableSqlLogEnable()) {
            return;
        }

        int parametersSize = statement.getParametersSize();
        if (parametersSize == 0) {
            this.statementLog("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) + "} executed. " + sql);
            return;
        }

        List<Object> parameters = new ArrayList<Object>(parametersSize);
        for (int i = 0; i < parametersSize; ++i) {
            JdbcParameter jdbcParam = statement.getParameter(i);
            parameters.add(jdbcParam.getValue());
        }

        String dbType = statement.getConnectionProxy().getDirectDataSource().getDbType();
        String formattedSql = SQLUtils.format(sql, dbType, parameters);
        this.statementLog("{conn-" + statement.getConnectionProxy().getId() + ", " + stmtId(statement) + "} executed. " + formattedSql);
    }

    /**
     * stmtId
     */
    protected String stmtId(StatementProxy statement) {
        StringBuffer buf = new StringBuffer();
        if (statement instanceof CallableStatementProxy) {
            buf.append("cstmt-");
        } else if (statement instanceof PreparedStatementProxy) {
            buf.append("pstmt-");
        } else {
            buf.append("stmt-");
        }
        buf.append(statement.getId());

        return buf.toString();
    }
}